/**********************************************************
 * ActionScript Development Tool 
 * Copyright (C) 2005 asdt.org 
 * 
 * http://www.asdt.org
 * http://sourceforge.net/projects/aseclipseplugin/
 *
 * This program is free software; 
 * you can redistribute it and/or modify it under the terms of 
 * the GNU General Public License as published by the 
 * Free Software Foundation; either version 2 of the License, 
 * or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License 
 * along with this program; if not, write to the 
 * Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 
 * 
 **********************************************************/

package ca.scotthyndman.as2haxe.dom;

import java.util.ArrayList;
import java.util.List;

/**
 * 
 * 
 * @author Peter Schreiber
 * @author Scott Hyndman (as2haxe)
 */
public class ASQualifiedName extends ASName {

	/**
	 * The "qualifier" structural property of this node type.
	 * 
	 * @since 3.0
	 */
	public static final ASChildPropertyDescriptor QUALIFIER_PROPERTY = new ASChildPropertyDescriptor(
			ASQualifiedName.class, "qualifier", ASName.class, true);

	/**
	 * The "name" structural property of this node type.
	 * 
	 * @since 3.0
	 */
	public static final ASChildPropertyDescriptor NAME_PROPERTY = new ASChildPropertyDescriptor(
			ASQualifiedName.class, "name", ASSimpleName.class, true);

	/**
	 * A list of property descriptors (element type:
	 * {@link ASPropertyDescriptor}), or null if uninitialized.
	 */
	private static final List<ASPropertyDescriptor> PROPERTY_DESCRIPTORS;

	static {
		List<Object> propertyList = new ArrayList<Object>(3);
		createPropertyList(ASQualifiedName.class, propertyList);
		addProperty(QUALIFIER_PROPERTY, propertyList);
		addProperty(NAME_PROPERTY, propertyList);
		PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
	}

	/**
	 * Returns a list of structural property descriptors for this node type.
	 * Clients must not modify the result.
	 * 
	 * @return a list of property descriptors (element type:
	 *         {@link ASPropertyDescriptor})
	 */
	public static List<ASPropertyDescriptor> propertyDescriptors() {
		return PROPERTY_DESCRIPTORS;
	}

	//
	// ======== MEMBERS
	//

	private ASName qualifier;

	private ASSimpleName name;

	//
	// ======== CONSTRUCTION
	//
	
	/**
	 * Constructs a new instance of ASQualifiedName
	 * 
	 * @param ast
	 *            The abstract syntax tree that owns this element
	 */
	public ASQualifiedName(AST ast) {
		super(ast);
	}

	public ASQualifiedName(AST ast, ASSimpleName name) {
		this(ast);

		setName(name);
	}

	//
	// ======== GETTERS / SETTERS
	//
	
	/**
	 * Returns the name part of this qualified name.
	 * 
	 * @return the name being qualified 
	 */ 
	public ASSimpleName getName() {
		return name;
	}

	/**
	 * Sets the name part of this qualified name to the given simple name.
	 * 
	 * @param name the identifier of this qualified name
	 * @exception IllegalArgumentException if:
	 * <ul>
	 * <li>the node belongs to a different AST</li>
	 * <li>the node already has a parent</li>
	 * </ul>
	 */ 
	public void setName(ASSimpleName name) {
		if (name == null) {
			throw new IllegalArgumentException();
		}
		ASTNode oldChild = this.name;
		preReplaceChild(oldChild, name, NAME_PROPERTY);
		this.name = name;
		postReplaceChild(oldChild, name, NAME_PROPERTY);
	}

	/**
	 * Returns the qualifier part of this qualified name.
	 * 
	 * @return the qualifier part of this qualified name
	 */ 
	public ASName getQualifier() {
		return qualifier;
	}

	/**
	 * Sets the qualifier of this qualified name to the given name.
	 * 
	 * @param qualifier the qualifier of this qualified name
	 * @exception IllegalArgumentException if:
	 * <ul>
	 * <li>the node belongs to a different AST</li>
	 * <li>the node already has a parent</li>
	 * <li>a cycle in would be created</li>
	 * </ul>
	 */ 
	public void setQualifier(ASName qualifier) {
		if (qualifier == null) {
			throw new IllegalArgumentException();
		}
		ASTNode oldChild = this.qualifier;
		preReplaceChild(oldChild, qualifier, QUALIFIER_PROPERTY);
		this.qualifier = qualifier;
		postReplaceChild(oldChild, qualifier, QUALIFIER_PROPERTY);
	}

	//
	// ======== INTERNAL GETTER SETTER
	//

	/*
	 * (omit javadoc for this method) Method declared on ASTNode.
	 */
	final ASTNode internalGetSetChildProperty(
			ASChildPropertyDescriptor property, boolean get, ASTNode child) {
		if (property == QUALIFIER_PROPERTY) {
			if (get) {
				return getQualifier();
			} else {
				setQualifier((ASName) child);
				return null;
			}
		}
		if (property == NAME_PROPERTY) {
			if (get) {
				return getName();
			} else {
				setName((ASSimpleName) child);
				return null;
			}
		}
		// allow default implementation to flag the error
		return super.internalGetSetChildProperty(property, get, child);
	}

	//
	// ======== STATICS
	//

	public static ASQualifiedName getDefault() {
		ASQualifiedName defaultName = new ASQualifiedName(ast);
		defaultName.setName(new ASSimpleName(ast, "Object"));
		return defaultName;
	}

	//
	// ======== OVERRIDES
	//

	@Override
	public String toString() {
		return ((qualifier != null) ? qualifier.toString() + "." : "")
				+ name.toString();
	}

	@Override
	public Object clone() {
		ASQualifiedName clone = new ASQualifiedName(getAST());
		clone.setName((ASSimpleName) getName().clone());

		if (getQualifier() != null) {
			clone.setQualifier((ASName) getQualifier().clone());
		}

		return clone;
	}

	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof ASQualifiedName)) {
			return false;
		}

		ASQualifiedName other = (ASQualifiedName) obj;
		ASName qToCall = null;
		ASName qOther = null;
		if (getQualifier() != null) {
			qToCall = getQualifier();
			qOther = other.getQualifier();
		} else if (other.getQualifier() != null) {
			qToCall = other.getQualifier();
			qOther = getQualifier();
		}

		return (qToCall != null ? qToCall.equals(qOther) : true)
				&& getName().equals(other.getName());
	}
}
